﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Domino;

namespace Streambolics.Notes
{
    /// <summary>
    ///     A Notes database.
    /// </summary>
    /// <remarks><para>
    ///     The Database object encapsulates the low-level NotesDocument object
    ///     exposed by the Notes COM Model.
    /// </para></remarks>

    public class Database
    {
        private NotesDatabase _Database;
        private Dictionary<NotesView, View> _ViewCache = new Dictionary<NotesView,View> ();

        /// <summary>
        ///     Create a Database object encapsulating a NotesDatabase.
        /// </summary>
        /// <param name="aDatabase">
        ///     The NotesDatabase to encapsulate.
        /// </param>

        internal Database (NotesDatabase aDatabase)
        {
            _Database = aDatabase;
        }

        /// <summary>
        ///     Opens a local database.
        /// </summary>
        /// <param name="aConnection">
        ///     The connection to use.
        /// </param>
        /// <param name="aName">
        ///     The name of the NSF file to use.
        /// </param>

        public Database (Connection aConnection, string aName)
            : this (aConnection.GetNotesDatabase (aName))
        {
        }

        /// <summary>
        ///     Opens a remote database.
        /// </summary>
        /// <param name="aConnection">
        ///     The connection to use.
        /// </param>
        /// <param name="aServer">
        ///     The name of the Notes Server.
        /// </param>
        /// <param name="aName">
        ///     The name of the NSF file to use.
        /// </param>

        public Database (Connection aConnection, string aServer, string aName)
            : this (aConnection.GetNotesDatabase (aServer, aName))
        {
        }

        #region Views

        /// <summary>
        ///     Create a View object corresponding to the given
        ///     NotesView.
        /// </summary>
        /// <param name="nv">
        ///     The NotesView to encapsulate.
        /// </param>
        /// <returns>
        ///     A View object of the appropriate type.
        /// </returns>
        /// <remarks><para>
        ///     The returned view does not need to be attached to the
        ///     database.
        /// </para></remarks>

        protected virtual View CreateView (NotesView nv)
        {
            return new View (nv);
        }

        internal View CachedView (object v)
        {
            NotesView nv = (NotesView)v;
            if (_ViewCache.ContainsKey (nv))
            {
                return _ViewCache[nv];
            }
            else
            {
                View rv = CreateView (nv);
                rv.Attach (this);
                _ViewCache.Add (nv, rv);
                return rv;
            }
        }

        internal object[] NotesViews
        {
            get
            {
                return (object[])(_Database.Views);
            }
        }

        /// <summary>
        ///     All views in the database.
        /// </summary>

        public IEnumerable<View> Views
        {
            get
            {
                foreach (var v in NotesViews)
                {
                    yield return CachedView (v);
                }
            }
        }

        #endregion

        #region Documents

        /// <summary>
        ///     Create a Document object encapsulating the NotesDocument.
        /// </summary>
        /// <param name="nd">
        ///     The NotesDocument to wrap.
        /// </param>
        /// <returns>
        ///     An appropriately typed Document object.
        /// </returns>
        /// <remarks><para>
        ///     The default implementation simply returns a generic Document
        ///     object.
        /// </para><para>
        ///     Redefine this method to return an object of the appropriate class.
        /// </para></remarks>

        protected virtual Document CreateDocument (NotesDocument nd)
        {
            return new Document (nd);
        }

        /// <summary>
        ///     Retrieves the Document object encapsulating the
        ///     NotesDocument.
        /// </summary>
        /// <param name="nd">
        ///     The NotesDocument to encapsulate.
        /// </param>
        /// <returns>
        ///     The Document object that encapsulates the NotesDocument.
        /// </returns>

        internal Document CachedDocument (NotesDocument nd)
        {
            return CreateDocument (nd);
        }

        #endregion
    }
}
